package com.fita.wechat.service.impl;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fita.entity.order.*;
import com.fita.entity.wallet.DistributionRewardRecord;
import com.fita.entity.wallet.TransactionRecord;
import com.fita.entity.wallet.UserWallet;
import com.fita.wechat.helper.impl.VehiclePriceHelper;
import com.fita.wechat.service.UserWalletService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.CollectionUtils;
import com.demo2do.core.utils.JsonUtils;
import com.fita.entity.agent.Agent;
import com.fita.entity.agent.AgentCompany;
import com.fita.entity.car.VehicleCategory;
import com.fita.entity.car.VehicleSize;
import com.fita.entity.coupon.Coupon;
import com.fita.entity.data.Country;
import com.fita.entity.data.CountryCoupon;
import com.fita.entity.data.ExchangeRate;
import com.fita.entity.data.Location;
import com.fita.entity.data.ShortUrl;
import com.fita.entity.data.SpecialEquipment;
import com.fita.entity.data.Supplier;
import com.fita.entity.data.VehicleParameter;
import com.fita.entity.dto.ehi.response.LocationDetailResponse;
import com.fita.entity.dto.ehi.response.SpecialEquipPrefe;
import com.fita.entity.dto.ehi.response.Telephones;
import com.fita.entity.dto.ehi.response.VehicleReservationResponse;
import com.fita.entity.set.Set;
import com.fita.wechat.dao.AgentDao;
import com.fita.wechat.dao.CarDao;
import com.fita.wechat.dao.CountryCouponDao;
import com.fita.wechat.dao.CountryDao;
import com.fita.wechat.dao.ExchangeRateDao;
import com.fita.wechat.dao.LocationDao;
import com.fita.wechat.dao.OrderDao;
import com.fita.wechat.dao.SetDao;
import com.fita.wechat.dao.SpecialEquipmentDao;
import com.fita.wechat.dao.SupplierDao;
import com.fita.wechat.entity.Shopping;
import com.fita.wechat.handler.EhiHandler;
import com.fita.wechat.handler.PDFHandler;
import com.fita.wechat.handler.PaymentHandler;
import com.fita.wechat.service.OrderService;
import com.fita.wechat.utils.ShortUrlUtils;

/**
 * 
 * @author 宋剑宏
 *
 */
@Service("orderService")
public class OrderServiceImpl extends DataServiceImpl<Order> implements OrderService {
    
    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;

    @Dao
    private OrderDao orderDao;
    
    @Dao
    private ExchangeRateDao exchangeRateDao;
    
    @Dao
    private SpecialEquipmentDao specialEquipmentDao;
    
    @Dao
    private CountryCouponDao countryCouponDao;
    
    @Dao
    private SupplierDao supplierDao;
    
    @Dao
    private AgentDao agentDao;
    
    @Dao
    private LocationDao locationDao;
    
    @Dao
    private CarDao carDao;
    
    @Dao
    private CountryDao countryDao;
    
    @Dao
    private SetDao setDao;
    
    @Autowired
    private PaymentHandler paymentHandler;
    
    @Autowired
    private EhiHandler ehiHandler;
    
    @Autowired
    private PDFHandler pdfHandler;
    
    @Value("#{ctx['ctx.domain']}")
    private String systemHost;

    @Autowired
    private UserWalletService userWalletService;

    @Autowired
    private VehiclePriceHelper vehiclePriceHelper;


    /*
     * (non-Javadoc)
     * 
     * @see
     * com.fita.wechat.service.OrderService#list(com.fita.entity.order.OrderStatus)
     */
    public List<Order> list(OrderStatus status) {
        return orderDao.listOrder(status);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.fita.wechat.service.OrderService#load(java.lang.Long)
     */
    public Order load(Long id) {
        return genericDaoSupport.load(Order.class, id);
    }
    
    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#load(java.lang.Long, java.lang.String, java.lang.String)
     */
    public Order load(Long orderId, String sign, String mobile) {
        
        Agent agent = agentDao.load(mobile);
        Order order = genericDaoSupport.load(Order.class, orderId);
        if(order == null || agent == null) {
            return null;
        }
        
        if(order.getAgent() != agent) {
            return null;
        }
        
        String signString = order.getBrand() + order.getBrand() + order.getCurrencyCode() + agent.getId() + order.getCountry();
        String signcurrent = DigestUtils.md5Hex(signString);
        if(!StringUtils.equalsIgnoreCase(signcurrent, sign)) {
            return null;
        }
        
        return order;
    }
    
    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#loadDetails(com.fita.entity.order.Order)
     */
    public OrderDetails loadDetails(Order order) {
        return orderDao.load(order);
    }
    
    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#loadSupplier(java.lang.String)
     */
    public Supplier loadSupplier(String supplierCode) {
        return supplierDao.load(supplierCode);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.fita.wechat.service.OrderService#update(java.lang.Long)
     */
    public void update(Long id) {
        Order order = genericDaoSupport.load(Order.class, id);
        genericDaoSupport.update(order.cancel());
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.fita.wechat.service.OrderService#pay(java.lang.Long)
     */
    public void pay(Long id) {
        Order order = genericDaoSupport.load(Order.class, id);
        genericDaoSupport.update(order.pay());

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.fita.wechat.service.OrderService#delete(java.lang.Long)
     */
    public void delete(Long id) {
        Order order = genericDaoSupport.load(Order.class, id);
        genericDaoSupport.update(order.delete());
    }
    
    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#create(com.fita.entity.agent.Agent, com.fita.wechat.entity.Shopping, com.fita.entity.dto.ehi.response.LocationDetailResponse)
     */
    public Order create(Agent agent, Shopping shopping, LocationDetailResponse locationDetail) {
        
        // 保存客户信息
        CustomerInfo customerInfo = new CustomerInfo(shopping.getFirstName(), shopping.getLastName(), shopping.getUserEmail(), shopping.getDriveAge(), shopping.getAirportNumber(), shopping.getUserPhone());
        genericDaoSupport.save(customerInfo.init());
        
        // 保存车辆详细信息
        CarInfo carInfo = new CarInfo(shopping.getCategoryCode(), 
                shopping.getSizeCode(), shopping.getDoorCount(),
                shopping.getAirConditionIn(), shopping.getTransmissionType(), 
                shopping.getModelName(), shopping.getModelCode(), shopping.getPicture(), 
                shopping.getPassengerQuantity(), shopping.getBaggageQuantity(), shopping.getSpecialEquipments(), shopping.getRateQualifier());
        genericDaoSupport.save(carInfo.init());
        
        // 保存订单详细信息
        Set set = genericDaoSupport.load(Set.class, shopping.getSetId());
        OrderDetails orderDetails = new OrderDetails(set.getCode(), customerInfo, carInfo);
        genericDaoSupport.save(orderDetails.init());
        
        // 保存订单信息
        Country country = genericDaoSupport.load(Country.class, shopping.getCountryId());
        Supplier supplier = genericDaoSupport.load(Supplier.class, shopping.getSupplierId());
        
        Location pickupLocation = genericDaoSupport.load(Location.class, shopping.getPickupLocation());
        Location returnLocation = genericDaoSupport.load(Location.class, shopping.getReturnLocation());
        
        Order order = new Order(agent, country.getCode(), shopping.getType(), supplier.getCode(), shopping.getCategoryCode(), shopping.getModelName(), shopping.getPicture(), pickupLocation.getName(), returnLocation.getName(), pickupLocation.getCode(), returnLocation.getCode(), shopping.getPickupDate(), shopping.getReturnDate());
        order.bindDetail(orderDetails);
        
        BigDecimal totalAmount = shopping.getTotalAmount();
        
        Country pickupCountry = countryDao.load(pickupLocation.getCountry());
        CountryCoupon coupon = countryCouponDao.load(pickupCountry, new Date());
        
        // 成本价($)
        int costPrice = this.getCostPrice(set, totalAmount);
        // 实际支付价格($)
        int payPrice = this.getPayPrice(set, agent.getCompany(), coupon, totalAmount);
        
        // 订单价格、货币、当前汇率
        String currencyCode = shopping.getCurrencyCode();
        ExchangeRate currentExchangeRate = exchangeRateDao.load(currencyCode, new Date());
        Long couponId = coupon != null ? coupon.getId() : null;
        int retailAmount = shopping.getRetailAmount().multiply(new BigDecimal(100)).intValue();
        order.generatePrice(totalAmount.multiply(new BigDecimal(100)).intValue(), agent.getCompany().getRate(), costPrice, payPrice, currencyCode, currentExchangeRate.getRate(), retailAmount, couponId);

        genericDaoSupport.save(order.init());

        // 一级代理提成
        Integer primaryAgentRate = agent.getCompany().getPrimaryAgentRate();
        if (primaryAgentRate != null){
            BigDecimal rateBigDecimal = new BigDecimal(primaryAgentRate).divide(new BigDecimal((100)));

            BigDecimal commissionPrice = null;

            //预付一级代理提成计算
            if (order.getType().isPrepay()){

                BigDecimal prepayDollar = new BigDecimal(order.getPayPrice()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);

                BigDecimal prepayRmb = prepayDollar.multiply(currentExchangeRate.getRate()).setScale(0, RoundingMode.UP);

                BigDecimal multiply = prepayRmb.multiply(new BigDecimal(100).add(new BigDecimal(primaryAgentRate)).divide(new BigDecimal(100))).setScale(0 ,RoundingMode.UP);

                // 代理提成
                commissionPrice = multiply.subtract(prepayRmb).multiply(new BigDecimal(0.975)).setScale(2, RoundingMode.HALF_UP);

            //到付一级代理提成计算
            }else if (order.getType().isArrivepay()){
                BigDecimal arriveCommissionOrderPrice = totalAmount.multiply(new BigDecimal(order.getAgentRate()).divide(new BigDecimal(100))).setScale(2, RoundingMode.HALF_UP);
                BigDecimal agentCommission = vehiclePriceHelper.getAgentCommission(totalAmount, country, order.getAgentRate(), primaryAgentRate);

                commissionPrice = arriveCommissionOrderPrice.subtract(agentCommission).multiply(currentExchangeRate.getRate()).multiply(new BigDecimal(0.975)).setScale(2, RoundingMode.HALF_UP);


            }else {
                throw BusinessException.newInstance("500", "订单错误");
            }

            commissionPrice = commissionPrice.multiply(new BigDecimal(100)).setScale(0, RoundingMode.UP);

            UserWallet userWallet = userWalletService.createOrLoadByMobile(agent.getMobile());

            UserWallet primaryAgentUserWallet = userWalletService.createOrLoadByMobile(agent.getCompany().getPrimaryAgent().getMobile());

            DistributionRewardRecord distributionRewardRecord = new DistributionRewardRecord(primaryAgentRate, commissionPrice.intValue(), primaryAgentUserWallet, order);

            genericDaoSupport.save(distributionRewardRecord);

            TransactionRecord transactionRecord = new TransactionRecord();

            transactionRecord.bindDistributionRewardRecord(distributionRewardRecord, primaryAgentUserWallet);

            genericDaoSupport.save(transactionRecord);

            order.bindDistributionRewardRecord(distributionRewardRecord);

            genericDaoSupport.update(order);
        }

        // 保存 orderSpecialEquipment
        if(StringUtils.isNoneBlank(order.getDetails().getCarInfo().getSpecialEquipments())) {
            String[] types = order.getDetails().getCarInfo().getSpecialEquipmentArray();
            List<SpecialEquipment> equipments = specialEquipmentDao.list(types);
            Map<String, com.fita.entity.dto.ehi.response.SpecialEquipment> equipmentResponses = CollectionUtils.constructMapValue(locationDetail.getSpecialEquipments(), "type");
            for(SpecialEquipment equipment : equipments) {
                OrderSpecialEquipment orderSpecialEquipment = new OrderSpecialEquipment(order, equipment, equipmentResponses.get(equipment.getType()));
                genericDaoSupport.save(orderSpecialEquipment);
            }
        }
        
        // 保存 orderVehicleFee
        String includeOrderFeeId = shopping.getIncludeOrderFeeId();
        this.saveOrderVehicleFee(includeOrderFeeId, true, order);
        String unIncludeOrderFeeId = shopping.getUnIncludeOrderFeeId();
        this.saveOrderVehicleFee(unIncludeOrderFeeId, false, order);
        
        // 保存 vehicleCharge
        String vehicleChargeId = shopping.getVehicleChargeId();
        this.saveOrderVehicleFee(vehicleChargeId, false, order);
        
        // 保存 order detail url
        String longUrl = systemHost + "/orders/" + order.getId();
        String shortUrl = ShortUrlUtils.getShortUrl(longUrl);
        ShortUrl shortUrlEntity = new ShortUrl(longUrl, shortUrl, false);
        genericDaoSupport.save(shortUrlEntity);
        
        // TODO Send sms to ??


        
        return order;
    }
    
    /**
     * 
     * @param orderFeeMessage
     * @param order
     */
    private void saveOrderVehicleFee(String orderFeeMessage, boolean include, Order order) {
        if(StringUtils.isNotBlank(orderFeeMessage)) {
            String[] orderFeeMessages = StringUtils.split(orderFeeMessage, ",");
            for(String message : orderFeeMessages) {
                String[] splitMessage = StringUtils.split(message, "|");
                
                // get vehicleParameter by id
                VehicleParameter parameter = genericDaoSupport.load(VehicleParameter.class, Long.parseLong(splitMessage[0]));
                
                OrderVehicleFee orderVehicleFee = new OrderVehicleFee(splitMessage[1], new BigDecimal(splitMessage[2]), include, order, parameter);
                genericDaoSupport.save(orderVehicleFee);
            }
        }
    }
    
    /**
     * 
     * @param set
     * @param intAmount
     * @return
     */
    private int getCostPrice(Set set, BigDecimal intAmount) {
        int costPrice = 0;
        
        // 到付或者Gross浮动价成本=API*80%
        if(set.getPayType().isArrivepay() || set.getPayType().isFloatPrepay()) {
            costPrice = intAmount.multiply(new BigDecimal(0.8*100)).intValue();
        } else {  // 常规价或者NET浮动价成本=API
            costPrice = intAmount.multiply(new BigDecimal(100)).intValue();
        }
        
        return costPrice;
    }
    
    /**
     * 
     * @param set
     * @param agentCompany
     * @param coupon
     * @param intAmount
     * @return
     */
    private int getPayPrice(Set set, AgentCompany agentCompany, CountryCoupon coupon, BigDecimal intAmount) {
        
        // 计算优惠券折后价格
        if(coupon != null) {
            intAmount = intAmount.multiply(new BigDecimal(coupon.getRate()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        }
        
        int payPrice = 0;
        
        // (1-返点率)*100
        BigDecimal currentRate = new BigDecimal(100).subtract(new BigDecimal(agentCompany.getRate()));
        
        // 到付或者Gross浮动价 = API*(1-返点率)
        if(set.getPayType().isArrivepay() || set.getPayType().isFloatPrepay()) {
            payPrice = intAmount.multiply(currentRate).intValue();
        } else if(set.getPayType().isDynamicPrepay()) { // NET浮动价 = API*117.6%*(1-返点率)
            payPrice = intAmount.multiply(new BigDecimal(1.176)).multiply(currentRate).intValue();
        } else {
            // 常规价格(美国或者加拿大) = API*125%*(1-返点率)
            payPrice = intAmount.multiply(new BigDecimal(1.25)).multiply(currentRate).intValue();
        }
        
        return payPrice;
    }
    
    /**
     * 
     * @param order
     * @return
     */
    private String saveOrderPdf(Order order) {
        Location pickupLocation = locationDao.load(order.getPickupLocation());
        Location returnLocation = locationDao.load(order.getReturnLocation());
        
        Set set = setDao.load(order.getDetails().getSetMeal());
        
        // list order special equipment
        List<OrderSpecialEquipment> equipments = specialEquipmentDao.list(order);
        
        // list order vehicle fee
        List<OrderVehicleFee> orderVehicleFees = this.listVehicleFee(order);
        Map<String, List<OrderVehicleFee>> vehicleFees = CollectionUtils.constructMapValues(orderVehicleFees, "include");
        
        String vehicleSize = VehicleSize.ssipOf(order.getDetails().getCarInfo().getModelCodeClass()).getChineseName();
        String vehicleCategory = VehicleCategory.codeOf(order.getDetails().getCarInfo().getCategoryCode()).getChineseName();
        
        String result = pdfHandler.saveOrderConfirm(order, pickupLocation, returnLocation, set, vehicleFees.get("true"), vehicleFees.get("false"), equipments, vehicleSize, vehicleCategory);
        
        // save pdf url
        String shortUrl = ShortUrlUtils.getShortUrl(result);
        ShortUrl shortUrlEntity = new ShortUrl(result, shortUrl, true);
        genericDaoSupport.save(shortUrlEntity);
        
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#staying(com.fita.entity.order.Order)
     */
    public Order staying(Order order) {
        genericDaoSupport.update(order.staying());
        
        // save shopping result url
        String longUrl = systemHost + "/shopping/result?orderId=" + order.getId() + "&type=pay";
        String shortUrl = ShortUrlUtils.getShortUrl(longUrl);
        ShortUrl shorturlEntity = new ShortUrl(longUrl, shortUrl, false);
        genericDaoSupport.save(shorturlEntity);

        // TODO call api create order here
        
        return order;
    }
    
    /* (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#paying(java.lang.Long)
     */
    public void paying(Long orderId) {
    	
    	Order order = genericDaoSupport.load(Order.class, orderId);
    	
    	order.changeStatus(OrderStatus.UNPAID);
    	
    	if (StringUtils.isNoneEmpty(order.getAlamoCode())) {
    		
			throw BusinessException.newInstance("500", "alamo订单号已生成");
		}
        
        // call api
        Map<String, Object> params = this.generateReservation(order);
        
        VehicleReservationResponse response = null;
        
		try {
			
			response = ehiHandler.vehicleReservation(params);
			
		} catch (BusinessException e) {
			
			// 订单异常，取消订单
			order.cancelOrder();
			
			logger.trace("#vehicleReservation() error. error is [{}]", e);
			
			throw e;
		}
        order.updateAlamoCode(response.getConfID());
        
        // 保存订单pdf
        String pdfUrl = this.saveOrderPdf(order);
        order.editPdfUrl(pdfUrl);
        
        genericDaoSupport.update(order);
    }
    
	/* (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#arrivePay(java.lang.Long)
	 */
	public void arrivePay(Long orderId) {
		
		Order order = genericDaoSupport.load(Order.class, orderId);
    	
    	order.changeStatus(OrderStatus.UNPAID);
    	
    	if (StringUtils.isNoneEmpty(order.getAlamoCode())) {
			throw BusinessException.newInstance("500", "alamo订单号已生成");
		}
        
        // call api
        Map<String, Object> params = this.generateReservation(order);
        
        VehicleReservationResponse response = ehiHandler.vehicleReservation(params);
        
        // save alamo code 
        order.updateAlamoCode(response.getConfID());
        
        // 保存订单pdf
        String pdfUrl = this.saveOrderPdf(order);
        order.editPdfUrl(pdfUrl);
        
        genericDaoSupport.update(order);
        		
	}

    @Override
    public void otherPay(Long orderId) {

        Order order = genericDaoSupport.load(Order.class, orderId);
        order.paid(0, OrderPayType.OFFLINE);
        genericDaoSupport.update(order);

        if(order.getUserCouponId() != null){

            Coupon coupon = genericDaoSupport.load(Coupon.class, order.getUserCouponId());
            coupon.use();
            genericDaoSupport.update(coupon);

        }

    }

    /**
     * @param secondaryAgentId
     * @return
     */
    public List<Order> listByAgentId(Long secondaryAgentId) {

        Agent agent = genericDaoSupport.load(Agent.class, secondaryAgentId);

        List<Order> orders = genericDaoSupport.searchForList("FROM Order WHERE disabled = false AND agent = :agent", "agent", agent);

        return orders;
    }

    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#prepay(com.fita.entity.order.Order, java.lang.String, java.lang.String, java.lang.Long, java.lang.String, java.lang.String)
     */
    public Map<String, Object> prepay(Order order, String openid, String remoteIp,Long couponId, String type, String callbackurl) {
        
        try {
            
            // 1. create payment request
            PaymentRequest paymentRequest = new PaymentRequest(order.getCode());
            genericDaoSupport.save(paymentRequest.initliaze());



            logger.trace("#prepay() - Get remote IP address [{}].", remoteIp);
            Map<String, Object> parameters = new HashMap<String, Object>();
            parameters.put("order_no", paymentRequest.getOrderCode());
            parameters.put("request_no", paymentRequest.getCode());
            parameters.put("user_id", openid);
            parameters.put("channel", "yoppay");
            parameters.put("channel_type", type);
            parameters.put("subject", "见闻租车订单支付");
            parameters.put("callback_url", callbackurl);
            //使用优惠券折价后的支付金额

            if(couponId !=null) {
                Coupon coupon = genericDaoSupport.load(Coupon.class, couponId);
            	parameters.put("amount", order.getCnyPayPrice(coupon.getAmount()).setScale(0, RoundingMode.UP).multiply(new BigDecimal(100)));
            }else {

            	parameters.put("amount", order.getCnyPayPrice().setScale(0, RoundingMode.UP).multiply(new BigDecimal(100)));
            }

            if (order.getDistributionRewardRecord() != null){
                BigDecimal amount = (BigDecimal) parameters.get("amount");
                amount.add(new BigDecimal(order.getDistributionRewardRecord().getAmount()));
            }

            parameters.put("subject", order.getBrand() + "租车费用");

            // 2. generate wechat pay context
            Map<String, Object> wechatPayContext = paymentHandler.generatePayContext(parameters);
            logger.trace("#prepay() - Get wechatPayContext here [{}]", JsonUtils.toJson(wechatPayContext));

            return wechatPayContext;

        } catch (Exception e) {
            logger.error("#prepay - occurs error", e);
            throw BusinessException.newInstance("500", "生成参数失败");
        }
    }


    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#handpay(com.fita.entity.order.Order, java.lang.String)
     */
    public Map<String, Object> handpay(Order order, String openid) {
        
        try {
            
            // 1. create payment request
            PaymentRequest paymentRequest = new PaymentRequest(order.getCode());
            genericDaoSupport.save(paymentRequest.initliaze());
            
            Map<String, Object> parameters = new HashMap<String, Object>();
            parameters.put("order_no", paymentRequest.getOrderCode());
            parameters.put("request_no", paymentRequest.getCode());
            parameters.put("user_id", openid);
            parameters.put("channel", "handpay");
           // parameters.put("amount", order.getCnyPayPrice().setScale(0, RoundingMode.UP).multiply(new BigDecimal(100)));
            parameters.put("subject", order.getBrand() + "租车费用");
            
            // 2. generate wechat pay context
            Map<String, Object> payContext = paymentHandler.generatePayContext(parameters);
            logger.trace("#prepay() - Get payContext here [{}]", JsonUtils.toJson(payContext));
            
            return payContext;
            
        } catch (Exception e) {
            logger.error("#prepay - occurs error", e);
            throw BusinessException.newInstance("500", "生成参数失败");
        }
    }

	/* (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#list(com.fita.entity.agent.Agent, com.fita.entity.order.OrderStatus)
	 */
	public List<Order> list(Agent agent, OrderStatus status) {
		
		// 已完成 显示完成和取消
		if (status.isConsumed()) {
			
			List<Order> orders = orderDao.list(agent, new OrderStatus[] {OrderStatus.CANCELED, OrderStatus.CONSUMED, OrderStatus.UNREFUNDED});
			
			return orders;
		}
		List<Order> orders = orderDao.list(agent, status);
		
		return orders;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#listSpecialEquipment(com.fita.entity.order.Order)
	 */
	public List<OrderSpecialEquipment> listSpecialEquipment(Order order) {
	    return specialEquipmentDao.list(order);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#listVehicleFee(com.fita.entity.order.Order)
	 */
	public List<OrderVehicleFee> listVehicleFee(Order order) {
		
		List<OrderVehicleFee> orderVehicleFees = carDao.listOrderVehicleFee(order);
		
		for (int i = 0; i < orderVehicleFees.size(); i++) {
			if (StringUtils.equals(orderVehicleFees.get(i).getVehicleParameter().getEnglishName(), "Drop Charge")) {
				Collections.swap(orderVehicleFees, i, 0);
				break;
			}
		}
	    return orderVehicleFees;
	}

	/* (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#cancelBooking(java.lang.Long)
	 */
	public void cancelBooking(Long orderId) {

		Order order = genericDaoSupport.load(Order.class, orderId);
		
		// 是否可以取消预定
		if (order.isCouldCancelBooking()) {
			
			order.cancelBooking();
			
		}else {
			
			throw BusinessException.newInstance("500", "已超过取消预定时间");
		}
		genericDaoSupport.update(order);
	}

	/* (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#cancelOrder(java.lang.Long)
	 */
	public void cancelOrder(Long orderId) {

		Order order = genericDaoSupport.load(Order.class, orderId);
		
		if (order.isCouldCancelOrder()) {
			
			order.cancelOrder();
			
			Map<String, Object> params = this.generateCancel(order);
			
            ehiHandler.vehicleReservationCancle(params);
            
		}else {
			
			throw BusinessException.newInstance("500", "已超过取消订单时间");
		}
		genericDaoSupport.update(order);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#generateReservation(com.fita.entity.order.Order)
	 */
	public Map<String, Object> generateReservation(Order order) {
	    Supplier supplier = supplierDao.load(order.getBrand());
        
        Location pickupLocation = locationDao.load(order.getPickupLocation());
        Location returnLocation = locationDao.load(order.getReturnLocation());
        
        if((supplier == null || supplier.getId() == null) || 
           (pickupLocation == null || pickupLocation.getId() == null) || 
           (returnLocation == null || returnLocation.getId() == null)) {
            logger.error("generateReservation occurs error : 查询参数异常, [{}]", JsonUtils.toJson(order));
            throw BusinessException.newInstance("500", "查询参数异常");
        }
        
        List<OrderSpecialEquipment> specialEquipments = specialEquipmentDao.list(order);
        
        // 取车时间和还车时间设成格林尼治时间
//        Date pickupDate = DateUtils.addHours(order.getPickupDate(), -8);
//        Date returnDate = DateUtils.addHours(order.getReturnDate(), -8);
        
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("brand", supplier.getCode());
        params.put("status", "Available");
        params.put("pickup_date_time", order.getPickupDate());
        params.put("return_date_time", order.getReturnDate());
        params.put("pickup_location", pickupLocation.getCode());
        params.put("return_location", returnLocation.getCode());
//        params.put("name_prefix", order.getCustomerPerfix());
        params.put("given_name", order.getCustomerName());
        params.put("surname", order.getCustomerPerfix());
//        params.put("name_suffix", order.getDetails().getCustomerInfo().getName());
        params.put("email", order.getDetails().getCustomerInfo().getEmail());
        
//        List<AddressesLines> addressesLines = new ArrayList<>();
//        addressesLines.add(new AddressesLines(pickupLocation.getAddressOne()));
//        params.put("address_lines", addressesLines);
        
        params.put("city_name", pickupLocation.getCityName());
        params.put("postal_code", pickupLocation.getPostalCode());
        params.put("state_code", pickupLocation.getState());
        params.put("country_name_code", pickupLocation.getCountry());
        params.put("vendor_pref_code", supplier.getPrefCode());
        params.put("air_condition_ind", order.getDetails().getCarInfo().getAirConditionIn());
        params.put("transmission_type", order.getDetails().getCarInfo().getTransmissionType());
        params.put("veh_type_category", order.getDetails().getCarInfo().getCategoryCode());
        params.put("door_counts", order.getDetails().getCarInfo().getDoorCount());
        params.put("veh_class_size", order.getDetails().getCarInfo().getSizeCode());
        params.put("driver_type_age", order.getDetails().getCustomerInfo().getAge());
        
        String rateQualifier = order.getDetails().getCarInfo().getRateQualifier();
        params.put("rate_qualifier", StringUtils.isNotBlank(rateQualifier) ? rateQualifier : "CORP");
        
        List<SpecialEquipPrefe> specialEquipPrefes = new ArrayList<>();
        for(OrderSpecialEquipment orderSpecialEquipment : specialEquipments) {
            specialEquipPrefes.add(new SpecialEquipPrefe(orderSpecialEquipment.getSpecialEquipment().getType(), new BigInteger("1")));
        }
        params.put("special_equip_prefes", specialEquipPrefes);
        
        if(StringUtils.equalsIgnoreCase(supplier.getCode(), "Enterprise")) {
            List<Telephones> telephones = new ArrayList<>();
            telephones.add(new Telephones("3", pickupLocation.getAreaCode(), order.getDetails().getCustomerInfo().getMobile(), "343"));
            params.put("telephones", telephones); 
        }
        
        Map<String, String> airportMessage = this.generateAirNumber(order.getDetails().getCustomerInfo().getFlightNumber());
        if(!MapUtils.isEmpty(airportMessage)) {
            String airCompanyCode = airportMessage.get("airCompanyCode");
            params.put("air_company_code", airCompanyCode);
            String arrivalDetailsNumber = airportMessage.get("arrivalDetailsNumber");
            params.put("arrival_details_number", arrivalDetailsNumber);
        }
        
        if(order.getType().isArrivepay()) {
            params.put("requestor_id", "AL021399");
        } else {
            params.put("requestor_id", "00000000");
        }
        
        // put sourceId
        params.put("source_id", order.getDetails().getSetMeal());
        
        //put order code
        if (order.getType().isPrepay()) {
            params.put("series_code", order.getCode());
		}
        logger.info("generateReservation success with result [{}]", JsonUtils.toJson(params));
        
        return params;
	}
	
	private Map<String, String> generateAirNumber(String airNumber){
	    Map<String, String> result = new HashMap<String, String>();
	    if(StringUtils.isNotBlank(airNumber)) {
	        int length = airNumber.length();
	        if(length >=2 && length <5) {
	            result.put("airCompanyCode", airNumber.substring(0, 2));
	        } else if(length == 5) {
	            result.put("airCompanyCode", airNumber.substring(0, 2));
	            result.put("arrivalDetailsNumber", airNumber.substring(2, 5));
	        } else if(length >5) {
	            result.put("airCompanyCode", airNumber.substring(0, 2));
                result.put("arrivalDetailsNumber", airNumber.substring(2, 6));
	        }
	    }
	    return result;
	}
 	
	/*
	 * (non-Javadoc)
	 * @see com.fita.wechat.service.OrderService#generateCancel(com.fita.entity.order.Order)
	 */
	public Map<String, Object> generateCancel(Order order) {
	    Supplier supplier = supplierDao.load(order.getBrand());
        
        if((supplier == null || supplier.getId() == null)) {
            logger.error("generateCancel occurs error : 查询参数异常, [{}]", JsonUtils.toJson(order));
            throw BusinessException.newInstance("500", "查询参数异常");
        }
        
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("status", "Available");
        params.put("cancel_type", "Cancel");
        params.put("unique_id", order.getAlamoCode());
        params.put("unique_type", "14");
        params.put("given_name", order.getCustomerName());
        params.put("surname", order.getCustomerPerfix());
        params.put("vendor_code", supplier.getPrefCode());
        
        logger.info("generateReservation success with result [{}]", JsonUtils.toJson(params));
        
        return params;
	}

}
